﻿// Copyright © 2011 Paul Vanukoff (pvanukoff@gmail.com)

using System;
using Bravura.Native.PluginBase.Waveforms;

namespace Bravura.Native.PluginBase.Oscillators
{
	/// <summary>
	/// An oscillator that uses a waveform. Amplitude, frequency and distortion are settable and modulatable.
	/// </summary>
	public class WaveformOscillator : Oscillator
	{
		#region Fields

		private Waveform _waveform = null;
		private double _angle = 0.0;
		private double _freqxdt = 1.0 / 480.0;

		#endregion

		/// <summary>
		/// Constructs a WaveformOscillator with the specified waveform and initial angle (for phase offsets).
		/// </summary>
		public WaveformOscillator(double dt, Waveform waveform, double angle) : base(dt)
		{
			_waveform = waveform;
			_angle = angle % 1.0;
			updateFreq();
		}

		#region Methods

		/// <summary>
		/// Sets the frequency.
		/// </summary>
		public override void SetFrequency(double val)
		{
			_freqBase = val;
			updateFreq();
		}

		/// <summary>
		/// Modulates the frequency.
		/// </summary>
		public override void ModulateFrequency(double val)
		{
			_freqMod = val;
			updateFreq();
		}

		private void updateFreq()
		{
			_freqxdt = _freqBase * _freqMod * _dt;
		}

		#endregion

		#region Implementation

		public override double Sample()
		{
			// calculate sample
			double s = _amplitude * _waveform.GetValue(_angle);

			// apply distortion ?
			if (_applyDist)
			{
				s = (s < 0.0) ? -Math.Pow(-s, _distortion) : Math.Pow(s, _distortion);
			}

			// update angle
			_angle = _angle + _freqxdt;
			if (_angle >= 1.0)
			{
				_angle = _angle % 1.0;
			}

			// return sample
			return s;
		}

		#endregion
	}
}
